import imgIcon from '@/assets/images/logo-universal.png';
import { Gone, Show } from '@/component/Display';
import { FloatGroup } from '@/component/FloatGroup';
import { LoginModal } from '@/component/Login';
import { views_factory } from '@/Factory';
import { GlobalValue } from '@/GlobalValue';
import { Theme } from '@/hooks/theme';
import { LayoutType } from '@/hooks/theme/LayoutType';
import { useOpenEditor } from '@/hooks/Workspaces/useOpenEditor';
import { sessions_mgr } from '@/mgr';
import { contacts_mgr } from '@/mgr/contact/ContactsMgr';
import { Paths } from '@/paths';
import cstyles from '@/styles/common.module.scss';
import { call_native } from '@/utils/call_native';
import { EditorView } from '@/views/EditorView';
import { IEditorInfo } from '@/views/EditorView/IEditorInfo';
import { ContextMenuKey } from '@/views/EditorView/TabBar';
import { ISlotRendererParams, IWorkspacesViewRef, Slot, WorkspacesView } from '@/views/WorkspacesView';
import { BugFilled, BugOutlined, IdcardOutlined, ReloadOutlined } from '@ant-design/icons';
import { Empty, Layout } from 'antd';
import ErrorBoundary from 'antd/es/alert/ErrorBoundary';
import useToken from 'antd/es/theme/useToken';
import { t } from 'i18next';
import QueryString from 'qs';
import React, { useEffect, useMemo, useRef, useState } from "react";
import { useLocation, useNavigate } from 'react-router';
import { ChatlogSettingsModal } from './ChatlogSettingsModal';
import { CloseButton } from './components/CloseButton';
import { FullscreenButton } from './components/FullscreenButton';
import MainNavMenu from './components/MainNavMenu';
import { MaximizeButton, toggle_maximize } from './components/MaximizeButton';
import { MinimizeButton } from './components/MinimizeButton';
import NavDropdown from './components/NavDropdown';
import SkinDropdown from './components/SkinDroupdown';
import { TopBarIconButton } from './components/TopBarIconButton';
import UserDropdown from './components/UserDropdown';
import { useNavConf } from './hooks/useNavConf';
import useNavItems from './hooks/useNavItems';
import { NavMenu } from './hooks/useNavMenu';
import styles from "./styles.module.scss";


export default function MainPage(): React.ReactElement {
  const ref_workspaces = useRef<IWorkspacesViewRef | null>(null);
  const navConf = useNavConf();
  const navItems = useNavItems(navConf)
  const [empty, set_empty] = useState(false)

  const [{ actived_slot, slot_infos, workspaces }, , dispatch] = GlobalValue.use()

  useEffect(() => {
    sessions_mgr().start()
    return () => sessions_mgr().stop()
  }, [sessions_mgr])

  useEffect(() => {
    contacts_mgr.start()
    return () => contacts_mgr.stop()
  }, [contacts_mgr])

  useEffect(() => {
    const workspaces = ref_workspaces.current?.workspaces;
    (window as any).workspaces = workspaces
    if (!workspaces) return;
    workspaces.debug_output = console.log
    workspaces.error_output = console.error
    workspaces.root.keep = true
    workspaces.root.type = 'h';
    dispatch([GlobalValue.Type.SetValue, ['workspaces', workspaces]])
  }, [])
  const nav = Paths.useNavigate();
  const [is_login_pending, set_is_login_pending] = useState(true);
  const [is_login_modal_open, set_is_login_modal_open] = useState(false)
  const { layoutType } = Theme.use();
  const { smallScreen } = GlobalValue.use(0);
  const [, token] = useToken()
  const copyright = t('copyright_notice').replace('%1', '' + new Date().getFullYear());
  const appName = t("app.name")
  const l = useLocation()
  const n = useNavigate()
  const [chatlong_settings_open, set_chatlong_settings_open] = useState(false);
  const search_obj = useMemo(() => {
    const { dev = __MODE__ === 'development', ...remain } = QueryString.parse(l.search.substring(1))
    const dev_v = ('' + dev).toLowerCase()
    const is_dev = !['0', 'false', ''].some(v => v === dev_v)
    document.body.classList[is_dev ? 'add' : 'remove']('dev')
    return { ...remain, dev: is_dev }
  }, [l])
  const open_editor = useOpenEditor();
  const navMenu = NavMenu.use("" as string, { navigate: (key) => open_editor({ kind: key, uid: key, title: '' }), defaultValue: [] });
  const header = (
    <Layout.Header className={styles.top_bar} style={{ backgroundColor: token.colorBgElevated }} onDoubleClick={toggle_maximize}>
      <Show yes={smallScreen}>
        <NavDropdown navMenu={navMenu} navItems={navItems} />
      </Show>
      <img className={styles.top_bar_ico} src={imgIcon} alt={appName} />
      <div className={styles.top_bar_title}>{appName}</div>
      <UserDropdown
        onClickLogin={() => set_is_login_modal_open(true)}
        pending={is_login_pending} />
      <SkinDropdown />
      <TopBarIconButton onClick={() => {
        const p = l.pathname + '?' + QueryString.stringify({ ...search_obj, dev: !search_obj.dev })
        n(p, { replace: true })
      }}>
        {search_obj.dev ? <BugFilled /> : <BugOutlined />}
      </TopBarIconButton>
      <TopBarIconButton onClick={() => set_chatlong_settings_open(true)}>
        <IdcardOutlined />
      </TopBarIconButton>
      <Show yes={!call_native.obj()}>
        <FullscreenButton />
      </Show>
      <Show yes={call_native.obj()}>
        <TopBarIconButton onClick={() => location.reload()}>
          <ReloadOutlined />
        </TopBarIconButton>
        <MinimizeButton />
        <MaximizeButton />
        <CloseButton />
      </Show>
    </Layout.Header >
  )
  const sider = (
    <Layout.Sider
      className={styles.side_bar}
      theme="light"
      collapsible
      collapsedWidth={navMenu.collapsedWidth}
      collapsed={navMenu.collapsed != false}
      onCollapse={navMenu.setCollapsed}>
      <MainNavMenu navMenu={navMenu} navItems={navItems} />
    </Layout.Sider>
  )
  const on_slots_changed = (slots: Slot[]) => {
    if (slots.length < 1) set_empty(true)
    else if (slots.length > 1) set_empty(false)
    else set_empty(!slots[0].id.startsWith('EDITORS#'))
  }
  const del_slots = (slots: GlobalValue.IEditorsSlotInfo[]) => {
    const workspaces = ref_workspaces.current?.workspaces;
    if (!workspaces) return;
    if (!slots.length) return;
    dispatch([GlobalValue.Type.DelSlotInfos, slots.map(v => v.id)])
    slots.forEach((s) => workspaces.del(s.id))
    workspaces.confirm()
  }
  const del_tabs_from_slot = (slot_info: GlobalValue.IEditorsSlotInfo, tabs: IEditorInfo[]) => {
    const remains_editors = slot_info.editors.filter(a => !tabs.some(b => a.uid == b.uid));

    if (!remains_editors.length) { // 一个都不剩下了，移除掉slot
      return del_slots([slot_info])
    }

    const old_editors = slot_info.editors;
    slot_info.editors = remains_editors;
    let { actived } = slot_info;
    if (!actived) {
      // 如果代码可以进到这，说明逻辑出了问题，应该时刻保持有actived的editor
      slot_info.actived = remains_editors[0];
      debugger;
    } else if (!remains_editors.some(a => a.uid === actived.uid)) {
      // 原本被打开的editor已被关闭，默认向前打开仍存在的editor，否则打开后面仍存在的editor。

      const start = old_editors.indexOf(actived)
      // 向前找
      for (let i = start - 1; i >= 0; --i) {
        const other = old_editors[i];
        if (!other || !remains_editors.some(a => a.uid === other.uid))
          continue;
        slot_info.actived = other;
        break;
      }

      // 向后找
      for (let i = start; i < old_editors.length; ++i) {
        const other = old_editors[i];
        if (!other || !remains_editors.some(a => a.uid === other.uid))
          continue;
        slot_info.actived = other;
        break;
      }
      if (!slot_info.actived) {
        // 如果代码可以进到这，说明逻辑出了问题，上面逻辑应当能保证此处actived不为空
        debugger;
      }
    }
    dispatch([GlobalValue.Type.SetSlotInfos, [slot_info]])
  }

  const add_tab_to_slot = (slot_info: GlobalValue.IEditorsSlotInfo, tab: IEditorInfo) => {
    const actived_idx = slot_info.editors.findIndex(v => v.uid === slot_info.actived?.uid)
    const new_slot_editors: IEditorInfo[] = [...slot_info.editors]
    new_slot_editors.splice(actived_idx + 1, 0, tab)
    const new_slot_info: GlobalValue.IEditorsSlotInfo = { ...slot_info, editors: new_slot_editors, actived: tab };
    dispatch([GlobalValue.Type.SetSlotInfos, [new_slot_info]])
  }

  const tab_as_new_slot = (anchor_slot_id: string, dock_type: "left" | "right" | "up" | "down", tab: IEditorInfo) => {
    const new_slot_id = 'EDITORS#' + views_factory.new_uid;
    const new_slot_info: GlobalValue.IEditorsSlotInfo = {
      id: new_slot_id,
      editors: [tab],
      actived: tab
    }
    ref_workspaces.current?.workspaces?.add(anchor_slot_id, dock_type, { id: new_slot_id })
    ref_workspaces.current?.workspaces?.confirm()
    dispatch([GlobalValue.Type.SetSlotInfos, [new_slot_info]])
  }

  const move_tab = (
    slot_a: GlobalValue.IEditorsSlotInfo,
    slot_b: GlobalValue.IEditorsSlotInfo,
    index: number,
    tab: IEditorInfo
  ) => {

    if (slot_a === slot_b) {
      const old_index = slot_a.editors.findIndex(v => v.uid === tab.uid)
      slot_a.editors = slot_a.editors.filter(v => v.uid !== tab.uid)
      slot_b.editors.splice(old_index > index ? index : index - 1, 0, tab)
    } else {
      slot_a.editors = slot_a.editors.filter(v => v.uid !== tab.uid)
      slot_b.editors.splice(index, 0, tab)
      if (!slot_a.editors.length) {
        ref_workspaces.current?.workspaces?.del(slot_a.id)
        ref_workspaces.current?.workspaces?.confirm()
      }
    }
    slot_b.actived = tab;
    const edited_slots = [slot_a, slot_b]
    dispatch([GlobalValue.Type.SetSlotInfos, edited_slots])
  }
  useEffect(() => {
    if (!workspaces) return;
    open_editor(
      Paths.All.LocalWXContacts,
      Paths.All.LocalWXSessions,
      Paths.All.About
    )
  }, [workspaces])

  const on_slots_actived = (slot: Slot) => {
    dispatch([GlobalValue.Type.SetActivedSlot, slot])
  }
  const ref_dragging_tab = useRef<[Slot, IEditorInfo] | undefined>(void 0)
  const slot_renderer = ({ slot, actived }: ISlotRendererParams) => {
    if (!slot.id.startsWith('EDITORS#')) return void 0;
    const slot_info = slot_infos[slot.id];
    if (!slot_info) return void 0;
    return (
      <EditorView
        ws_slot={slot}
        actived={actived?.id == slot.id}
        ref_dragging={ref_dragging_tab}
        on_tab_drag_start={v => ref_dragging_tab.current = [slot, v]}
        on_tab_drag_end={v => ref_dragging_tab.current = void 0}
        on_somethings_drop_to_content={(dock_type) => {
          const workspaces = ref_workspaces.current?.workspaces
          if (!workspaces) return;
          if (!ref_dragging_tab.current) return;
          const [src_slot, tab] = ref_dragging_tab.current;
          if (src_slot === slot && dock_type == 'full') return;

          const src_slot_info = slot_infos[src_slot.id];
          if (!src_slot_info) return;
          del_tabs_from_slot(src_slot_info, [tab])
          if (dock_type === 'full') return add_tab_to_slot(slot_info, tab)
          tab_as_new_slot(slot_info.id, dock_type, tab)
        }}

        on_somethings_drop_to_tabs={([index]) => {
          if (!ref_dragging_tab.current) return;
          const [src_slot, tab] = ref_dragging_tab.current;
          const src_slot_info = slot_infos[src_slot.id];
          if (!src_slot_info) return;
          move_tab(src_slot_info, slot_info, index, tab);
        }}

        on_dropdown_item_click={(key, editor) => {
          if (!editor) return;
          switch (key) {
            case ContextMenuKey.关闭:
              del_tabs_from_slot(slot_info, [editor]);
              break;
            case ContextMenuKey.关闭其他:
              del_tabs_from_slot(slot_info, slot_info.editors.filter(v => v.uid !== editor.uid))
              break;
            case ContextMenuKey.关闭左侧全部: {
              const editors = []
              for (const v of slot_info.editors) {
                if (v.uid !== editor.uid) editors.push(v)
                else break;
              }
              del_tabs_from_slot(slot_info, editors)
              break
            }
            case ContextMenuKey.关闭右侧全部: {
              const editors = []
              for (const v of slot_info.editors.toReversed()) {
                if (v.uid !== editor.uid) editors.push(v)
                else break;
              }
              del_tabs_from_slot(slot_info, editors)
              break
            }
            case ContextMenuKey.关闭全部:
              del_slots([slot_info])
              break;
          }
        }}
      />
    )
  }

  return (
    <FloatGroup.Provider>
      <Layout className={styles.main_root}>
        <Show yes={layoutType === LayoutType.sidebar_main}>{sider}</Show>
        <Show yes={layoutType === LayoutType.topbar_main}>{header}</Show>
        <Layout className={styles.main_zone}>
          <Show yes={layoutType === LayoutType.sidebar_main}>{header}</Show>
          <Show yes={layoutType === LayoutType.topbar_main}>{sider}</Show>
          <div className={styles.body_zone}>
            <ErrorBoundary>
              <WorkspacesView
                _ref={ref_workspaces}
                on_slots_changed={on_slots_changed}
                on_slot_actived={on_slots_actived}
                actived_slot={actived_slot}
                children={slot_renderer} />
              <Gone yes={!empty}>
                <Empty description={copyright} className={cstyles.empty_and_fill} />
              </Gone>
              <ChatlogSettingsModal
                styles={{
                  wrapper: { position: 'absolute' },
                  mask: { position: 'absolute' },
                }}
                getContainer={() => {
                  const container = document.querySelector(`.${styles.main_zone}>.${styles.body_zone}`) as HTMLElement
                  return container
                }}
                open={chatlong_settings_open}
                onCancel={() => set_chatlong_settings_open(false)} />
              <Show yes={call_native.obj()}>
              </Show>
            </ErrorBoundary>
          </div>
        </Layout>
      </Layout>
      <LoginModal
        open={is_login_modal_open}
        on_pending={set_is_login_pending}
        onCancel={() => set_is_login_modal_open(false)}
        on_resolve={() => set_is_login_modal_open(false)} />
    </FloatGroup.Provider>
  )
}

